﻿namespace CPL
{
    using System;
    using System.Collections.Generic;

    internal static class Partitioner
    {
        internal class PartitionRange
        {
            public int UpperBound;
            public int LowerBound;
            public int Step;
        }

        internal static List<PartitionRange> GetRanges(
            int lowerBound,
            int upperBound,
            int step,
            int maxParallelismLevel,
            PartitionerType partitionerType)
        {
            switch (partitionerType)
            {
                case PartitionerType.Increasing:
                case PartitionerType.Decreasing:
                case PartitionerType.Wise:
                case PartitionerType.Equal:
                    return EqualRanges(
                        lowerBound,
                        upperBound,
                        step,
                        maxParallelismLevel);
                default:
                    return EqualRanges(
                        lowerBound,
                        upperBound,
                        step,
                        maxParallelismLevel);
            }
        }

        private static List<PartitionRange> EqualRanges(
            int lowerBound,
            int upperBound,
            int step,
            int partitionsCount)
        {
            var partitions = new List<PartitionRange>(partitionsCount);

            var rangeSize = (int)Math.Round(((upperBound - lowerBound) / (double) partitionsCount) + 0.5);
            var rangeLowerBound = 0;

            for (var i = 0; i < partitionsCount; i++)
            {
                var rangeUpperBound = 0;

                for (var j = rangeLowerBound; j < rangeLowerBound + rangeSize; j++)
                {
                    if (j >= upperBound)
                    {
                        break;
                    }

                    rangeUpperBound = j;
                }

                var partition = new PartitionRange
                                    {
                                        LowerBound = rangeLowerBound,
                                        UpperBound = rangeUpperBound,
                                        Step = step
                                    };

                partitions.Add(partition);
                rangeLowerBound += rangeSize;
            }

            return partitions;
        }
    }
}